package pl.edu.agh.gt.stock;

import org.apache.log4j.Logger;

import pl.edu.agh.gt.data.Rate;
import pl.edu.agh.gt.data.TradingHistory;
import pl.edu.agh.gt.ga.Genotype;
import pl.edu.agh.gt.gui.ChartDisplay;
import pl.edu.agh.gt.strategy.BuyAndHold;
import pl.edu.agh.gt.strategy.Context;
import pl.edu.agh.gt.strategy.Strategy;

public class Trader {
	
	private final static Logger log = Logger.getLogger(Trader.class);
	
	public final static float INITIAL_VALUE = 10000;
	
	/**
	 * These public parameters should be only accessed for read
	 * XXX refactor to TraderStats
	 */
	public String name;
	public float baseCurrency; // base currency ammount USD
	public float quoteCurrency; // trading currency ammount EUR
	public float invested;
	
	public float maxInvested = 0;
	public int buyActions = 0;
	public int sellActions = 0;
	public int closeActions = 0;
	public int inTheMarket = 0;

	protected Context ctx;
	protected Strategy strategy;
	
	protected TradingHistory tradingHistory;//XXX move to listener
	protected boolean logTrading = false;  // performance impact!
	protected TraderListener listener;
	
	public Trader(String n, Stock stock, Strategy strategy) {
		this.name = n;
		this.strategy = strategy;
		this.ctx = new Context(stock.getRatesHistory(), stock.getBroker(), this);
		this.baseCurrency = INITIAL_VALUE;
		this.quoteCurrency = 0;
		this.invested = 0;
	}

	public void trade(int iteration) {
		
		Rate currRate = ctx.history.getRate(iteration);
		
		float totalWorth = evaluate(currRate);
		
		log.debug("Trader "+name+", baseCurrency = "+baseCurrency+", quoteCurrency = "+quoteCurrency + ", total: "+totalWorth);
		
		if(logTrading) {
			if(tradingHistory == null)
				tradingHistory = new TradingHistory(); 
			tradingHistory.add(baseCurrency, quoteCurrency, totalWorth); // performance impact!
		}
		
		strategy.decide(iteration,currRate,ctx);
		
	}
	
	public float evaluate(Rate rate) {
		return baseCurrency + ctx.broker.bid(rate, quoteCurrency);
	}
	
	public void buy(float base, Rate rate) {
		if(listener != null)
			listener.onBuy(this, base, rate);
		
		buyActions++;
		inTheMarket++;
		// validate ammount
		base = Math.min(base, baseCurrency);
		baseCurrency -= base;
		quoteCurrency += ctx.broker.ask(rate, base);
		invested += base;
		if(invested > maxInvested)
			maxInvested = invested;
		assert baseCurrency >= 0;
		
		if(listener != null)
			listener.onBuy(this, base, rate);
		
	}
	
	public void sell(float quote, Rate rate) {
		
		sellActions++;
		inTheMarket++;
		// validate ammount
		quote = Math.min(quote, quoteCurrency);
		quoteCurrency -= quote;
		float trade = ctx.broker.bid(rate, quote);
		baseCurrency  += trade;
		invested -= trade;
		assert quoteCurrency >= 0;
		
		if(listener != null)
			listener.onSell(this, quote, rate);
		
	}
	
	public void close(Rate rate) {
		
		closeActions++;
		baseCurrency += ctx.broker.bid(rate, quoteCurrency);
		quoteCurrency = 0;
		invested = 0;
		inTheMarket = 0;
		
		if(listener != null)
			listener.onClose(this, rate);
		
	}

	public boolean isLogTrading() {
		return logTrading;
	}

	public void setLogTrading(boolean logTrading) {
		this.logTrading = logTrading;
	}

	public Strategy getStrategy() {
		return strategy;
	}
	
	public void setStrategy(Strategy s) {
		strategy = s;
	}

	public TradingHistory getTradingHistory() {
		return tradingHistory;
	}

	public void setListener(TraderListener listener) {
		this.listener = listener;
	}

	public TraderListener getListener() {
		return listener;
	}

}
